#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
股票交易分析系统 - Web应用控制器
基于FastAPI框架，专注于推荐股票可视化功能
职责：路由处理、请求响应、模板渲染
"""

from fastapi import FastAPI, Request, HTTPException
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse, JSONResponse
import json
import logging
from typing import Dict, Any
import uvicorn
from datetime import datetime

# 导入项目模块
from services.webapp_service import WebAppService
from services.trade_service import TradeService
from models.response_model import ApiResponseHelper
from config.config import LOG_CONFIG

# 配置日志 - 使用与主系统相同的日志配置
from utils.logger import setup_logger
setup_logger()
logger = logging.getLogger(__name__)

# 创建FastAPI应用
app = FastAPI(
    title="股票推荐可视化系统",
    description="专注于股票推荐数据的实时可视化展示",
    version="1.0.0"
)

# 配置模板和静态文件
templates = Jinja2Templates(directory="templates")
app.mount("/static", StaticFiles(directory="static"), name="static")

# 初始化服务
webapp_service = WebAppService()
trade_service = TradeService()

def _apply_sorting(data: Dict[str, Any], sort_by: str, sort_order: str) -> Dict[str, Any]:
    """
    对推荐数据应用排序
    
    Args:
        data: 原始数据
        sort_by: 排序字段 (energy_value, change_percent, volume)
        sort_order: 排序方向 (asc, desc)
        
    Returns:
        排序后的数据
    """
    reverse = sort_order.lower() == "desc"
    
    def safe_sort_key(stock):
        """安全的排序键函数，处理None值"""
        value = stock.get(sort_by)
        if value is None:
            # None值统一处理：对于降序，None排在最后；对于升序，None排在最后
            return float('-inf') if reverse else float('inf')
        try:
            return float(value)
        except (ValueError, TypeError):
            return float('-inf') if reverse else float('inf')
    
    # 对各个列表进行排序
    if "top_30" in data and data["top_30"]:
        data["top_30"] = sorted(data["top_30"], key=safe_sort_key, reverse=reverse)
    
    if "bottom_30" in data and data["bottom_30"]:
        data["bottom_30"] = sorted(data["bottom_30"], key=safe_sort_key, reverse=reverse)
    
    if "continuous_monitoring" in data and data["continuous_monitoring"]:
        data["continuous_monitoring"] = sorted(data["continuous_monitoring"], key=safe_sort_key, reverse=reverse)
    
    return data

@app.get("/", response_class=HTMLResponse)
@app.get("/recommendations", response_class=HTMLResponse)
async def recommendations_page(request: Request):
    """股票推荐可视化页面 - 支持多个路由"""
    return templates.TemplateResponse("recommendations.html", {
        "request": request,
        "title": "股票推荐可视化",
        "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    })

@app.get("/api/recommendations", response_class=JSONResponse)
async def get_recommendations(target_date: str = None, sort_by: str = "default", sort_order: str = "desc") -> Dict[str, Any]:
    """
    获取推荐股票数据API - 统一返回格式
    
    Args:
        target_date: 目标日期，格式YYYY-MM-DD
        sort_by: 排序字段，可选值：default(默认), energy_value(能量值), change_percent(当前涨幅), volume(成交量)
        sort_order: 排序方向，可选值：desc(降序), asc(升序)
        
    Returns:
        包含排序后股票数据的JSON响应
    """
    import time
    start_time = time.time()
    
    try:
        # 参数验证
        valid_sort_fields = ["default", "energy_value", "change_percent", "volume"]
        valid_sort_orders = ["asc", "desc"]
        
        if sort_by not in valid_sort_fields:
            return ApiResponseHelper.error(
                code=400,
                msg=f"排序字段错误，支持的值: {', '.join(valid_sort_fields)}，当前输入: {sort_by}"
            )
        
        if sort_order not in valid_sort_orders:
            return ApiResponseHelper.error(
                code=400,
                msg=f"排序方向错误，支持的值: {', '.join(valid_sort_orders)}，当前输入: {sort_order}"
            )
        
        # 解析日期参数
        date_parse_start = time.time()
        parsed_date = None
        if target_date:
            try:
                parsed_date = datetime.strptime(target_date, '%Y-%m-%d').date()
            except ValueError:
                return ApiResponseHelper.error(
                    code=400, 
                    msg=f"日期格式错误，请使用 YYYY-MM-DD 格式，当前输入: {target_date}"
                )
        date_parse_time = (time.time() - date_parse_start) * 1000
        
        # 获取推荐数据
        data_fetch_start = time.time()
        raw_data = webapp_service.get_today_recommendations(parsed_date)
        data_fetch_time = (time.time() - data_fetch_start) * 1000
        
        # 数据处理和排序
        process_start = time.time()
        
        # 应用排序（如果指定了排序字段）
        if sort_by != "default":
            raw_data = _apply_sorting(raw_data, sort_by, sort_order)
        
        raw_data["total_count"] = len(raw_data.get("top_30", [])) + len(raw_data.get("bottom_30", []))
        process_time = (time.time() - process_start) * 1000
        
        # 计算总响应时间
        total_time = (time.time() - start_time) * 1000
        
        # 记录性能日志
        sort_info = f", 排序: {sort_by}({sort_order})" if sort_by != "default" else ""
        logger.info(f"📊 API响应时间: {total_time:.2f}ms (数据获取: {data_fetch_time:.2f}ms, 数据处理: {process_time:.2f}ms){sort_info}")
        
        return ApiResponseHelper.success(
            data=raw_data,
            msg="获取推荐数据成功"
        )
        
    except Exception as e:
        total_time = (time.time() - start_time) * 1000
        logger.error(f"获取推荐数据失败 (耗时: {total_time:.2f}ms): {e}")
        return ApiResponseHelper.error(
            code=500,
            msg=f"获取推荐数据失败: {str(e)}"
        )



@app.get("/api/health", response_class=JSONResponse)
async def health_check() -> Dict[str, Any]:
    """健康检查接口 - 统一返回格式"""
    try:
        health_data = webapp_service.check_system_health()
        
        if health_data.get("status") == "healthy":
            return ApiResponseHelper.success(
                data=health_data,
                msg="系统运行正常"
            )
        else:
            return ApiResponseHelper.error(
                code=503,
                msg="系统异常",
                data=health_data
            )
        
    except Exception as e:
        logger.error(f"健康检查失败: {e}")
        return ApiResponseHelper.error(
            code=500,
            msg=f"健康检查失败: {str(e)}"
        )

@app.post("/api/execute-buy")
async def execute_buy_task(target_date: str = None) -> Dict[str, Any]:
    """执行买入任务API"""
    import time
    start_time = time.time()
    
    try:
        # 解析日期参数
        parsed_date = None
        if target_date:
            try:
                parsed_date = datetime.strptime(target_date, '%Y-%m-%d').date()
            except ValueError:
                return ApiResponseHelper.error(
                    code=400, 
                    msg=f"日期格式错误，请使用 YYYY-MM-DD 格式，当前输入: {target_date}"
                )
        
        # 执行买入任务
        logger.info(f"Web API触发买入任务，目标日期: {parsed_date or '今日'}")
        trade_service.execute_buy_task(parsed_date)
        
        # 计算总响应时间
        total_time = (time.time() - start_time) * 1000
        logger.info(f"🟢 买入任务API执行完成，耗时: {total_time:.2f}ms")
        
        return ApiResponseHelper.success(
            data={
                "target_date": target_date or datetime.now().strftime('%Y-%m-%d'),
                "execution_time": f"{total_time:.2f}ms"
            },
            msg="买入任务执行完成"
        )
        
    except Exception as e:
        total_time = (time.time() - start_time) * 1000
        logger.error(f"买入任务执行失败 (耗时: {total_time:.2f}ms): {e}")
        return ApiResponseHelper.error(
            code=500,
            msg=f"买入任务执行失败: {str(e)}"
        )

@app.post("/api/execute-sell")
async def execute_sell_task(target_date: str = None) -> Dict[str, Any]:
    """执行收盘统计任务API"""
    import time
    start_time = time.time()
    
    try:
        # 解析日期参数
        parsed_date = None
        if target_date:
            try:
                parsed_date = datetime.strptime(target_date, '%Y-%m-%d').date()
            except ValueError:
                return ApiResponseHelper.error(
                    code=400, 
                    msg=f"日期格式错误，请使用 YYYY-MM-DD 格式，当前输入: {target_date}"
                )
        
        # 执行收盘统计任务
        logger.info(f"Web API触发收盘统计任务，目标日期: {parsed_date or '今日'}")
        trade_service.execute_sell_task(parsed_date)
        
        # 计算总响应时间
        total_time = (time.time() - start_time) * 1000
        logger.info(f"🟢 收盘统计任务API执行完成，耗时: {total_time:.2f}ms")
        
        return ApiResponseHelper.success(
            data={
                "target_date": target_date or datetime.now().strftime('%Y-%m-%d'),
                "execution_time": f"{total_time:.2f}ms"
            },
            msg="收盘统计任务执行完成"
        )
        
    except Exception as e:
        total_time = (time.time() - start_time) * 1000
        logger.error(f"收盘统计任务执行失败 (耗时: {total_time:.2f}ms): {e}")
        return ApiResponseHelper.error(
            code=500,
            msg=f"收盘统计任务执行失败: {str(e)}"
        )

if __name__ == "__main__":
    # 开发环境启动
    uvicorn.run(
        "web_app:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
        log_level="info"
    )
